use sqlx::{migrate, query, query_as, FromRow, PgPool};
use std::error::Error;

#[derive(Debug, FromRow)]
pub struct Demo {
  pub title: String,
  pub author: String,
  pub isbn: String,
}

async fn insert(pool: &PgPool, demo: &Demo) -> Result<(), Box<dyn Error>> {
  let mut txn = pool.begin().await?;
  let author_q = r"
    insert into author (name) values ($1) returning id
  ";

  let demo_q = r"
    insert into demo (title, author, isbn) values ($1, $2, $3)
  ";

  let author_id: (i64,) = query_as(author_q)
    .bind(&demo.author)
    .fetch_one(&mut txn)
    .await?;

  query(demo_q)
    .bind(&demo.title)
    .bind(&author_id.0)
    .bind(&demo.isbn)
    .execute(&mut txn)
    .await?;

  txn.commit().await?;
  // txn.rollback().await?;
  Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
  let url = "postgres://postgres:postgres@127.0.0.1:5432/test_demo";
  let pool = PgPool::connect(url).await?;
  // 创建表
  migrate!("./migrations").run(&pool).await?;

  let demo = Demo {
    title: "Rust Book".to_string(),
    author: "Jerry".to_string(),
    isbn: "isbn-xxx-abxx".to_string(),
  };

  insert(&pool, &demo).await?;

  Ok(())
}
